package org.apache.catalina.startup;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.catalina.Server;
import org.apache.catalina.connector.Connector;
import org.apache.tomcat.util.digester.Digester;
import org.apache.tomcat.util.file.ConfigFileLoader;
import org.apache.tomcat.util.file.ConfigurationSource;
import org.xml.sax.InputSource;

/**
 * 与开始/关闭shell脚本交互的主类，因此如果要研究启动和关闭的过程，就从这个类开始看起。
 *
 * @author chentudong
 * @date 2024/2/19 11:46
 * @since 1.0
 */
public class Catalina {

  public static final String SERVER_XML = "conf/server.xml";

  protected String configFile = SERVER_XML;

  protected ClassLoader parentClassLoader = Catalina.class.getClassLoader();

  /**
   * The server component we are starting or stopping.
   * 整个tomcat概念中，server组件全局只有一个，最先启动的也是它！最后停止的也是它！
   */
  protected Server server = null;

  public void load() {
    parseServerXml(true);
  }

  /**
   * parseServerXml
   *
   * @param start start
   */
  private void parseServerXml(boolean start) {
    ConfigFileLoader.setSource(
        new CatalinaBaseConfigurationSource(Bootstrap.getCatalinaBaseFile(), getConfigFile()));
    File file = configFile();
    try (ConfigurationSource.Resource resource = ConfigFileLoader.getSource().getServerXml()) {
      Digester digester = start ? createStartDigester() : createStopDigester();
      InputSource inputSource = new InputSource(resource.getURI().toURL().toString());
      inputSource.setByteStream(resource.getInputStream());
      digester.push(this);
      digester.parse(inputSource);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  public Digester createStartDigester() {
    Digester digester = new Digester();
    // digester对象在解析server.xml中的属性并实例化他们时，用的类加载器是否是从线程上下文中拿的，默认是false，这里设置为true
    digester.setUseContextClassLoader(true);
    digester.addObjectCreate("Server",
        "org.apache.catalina.core.StandardServer",
        "className");
    digester.addSetProperties("Server");
    return digester;
  }

  public Digester createStopDigester() {
    return null;
  }

  public String getConfigFile() {
    return configFile;
  }

  /**
   * 读取 conf/server.xml
   *
   * @return File
   */
  public File configFile() {
    File file = new File(configFile);
    if (!file.isAbsolute()) {
      file = new File(Bootstrap.getCatalinaBase(), configFile);
    }
    return file;
  }

  public ClassLoader getParentClassLoader() {
    return parentClassLoader;
  }

  public void setParentClassLoader(ClassLoader parentClassLoader) {
    this.parentClassLoader = parentClassLoader;
  }
}
